# -*- coding: utf-8 -*-
"""
@Time ： 2020/11/16 20:58
@Auth ： Mr. William 1052949192
@Company ：特斯汀学院 @testingedu.com.cn
@Function ：HTTP接口测试关键字库
"""
import json
import traceback
import requests
import jsonpath
from common.Logger import logger


class Inter:
    """
    特斯汀学院通用接口测试关键字类
    """

    def __init__(self, writer):
        """
        """
        # session管理，可以自动关联请求头和响应头
        self.session = requests.session()
        # 保留本次发包的结果
        self.res = {}
        # 保留url地址前缀
        self.url = ''
        # 需要关联的字典
        self.relations = {}
        # 传入写入结果的对象
        self.writer = writer

    def reauth(self):
        """
        针对特斯汀接口项目重新授权的关键字
        :return:
        """
        try:
            self.session.post('http://testingedu.com.cn:8081/inter/HTTP/logout')
            # 获取token
            result = self.session.post('http://testingedu.com.cn:8081/inter/HTTP/auth')
            # 添加token到头里面去
            token = json.loads(result.text)['token']
            self.session.headers['token'] = token
            self.__write_excel(1, '授权成功')
        except Exception as e:
            self.__write_excel(0, traceback.format_exc())

    def seturl(self, url=''):
        """
        设置公司url的通用前缀
        :param url: url的通用部分
        :return:
        """
        if not url.startswith('http'):
            self.__write_excel(1, url + '格式存在问题，请检查')
            self.url = url
        else:
            self.url = url
            self.__write_excel(1, url)

    def addheader(self, key='', value=''):
        """
        往会话里面添加头部键值对
        :param key: 头部的键
        :param value: 头部值
        :return:
        """
        self.session.headers[key] = self.get_relation(value)
        self.__write_excel(1, self.session.headers)

    def removeheader(self, key=''):
        """
        往会话里面添加头部键值对
        :param key: 头部的键
        :param value: 头部值
        :return:
        """
        try:
            self.session.headers.pop(key)
            self.__write_excel(1, self.session.headers)
        except Exception as e:
            self.__write_excel(1, self.session.headers)

    def clearcookie(self):
        """
        清空会话的cookie
        :return:
        """
        try:
            self.session.cookies.clear()
            self.__write_excel(1, self.session.cookies)
        except Exception as e:
            self.__write_excel(1, self.session.cookies)

    def post(self, url='', params=None):
        """
        以post形式发送请求
        :param url: 接口的url地址
        :param params: 参数，可以不填
        :return:
        """
        # 处理，如果传的不是绝对的url地址，需要拼上通用前缀
        if not url.startswith('http'):
            url = self.url + '/' + url

        if params is None or params == '':
            params = None

        # 需要先关联
        params = self.get_relation(params)
        # 标识接口的参数类型，0是键值对参数，1是json
        api_type = 0
        if params is not None and params.startswith('{"'):
            api_type = 1

        if api_type == 0:
            # 获取字典格式的参数
            params = self.str_to_dict(params)

        try:
            # 处理url地址出问题，或者接口超时等情况
            if api_type == 0:
                result = self.session.post(url, data=params)
            else:
                result = self.session.post(url, json=json.loads(params))
        except Exception as e:
            self.res = traceback.format_exc()
            self.__write_excel(0, self.res)
            return

        try:
            # 将结果处理为json结果
            self.res = json.loads(result.text)
            self.__write_excel(1, self.res)
        except Exception as e:
            self.res = result.text
            self.__write_excel(0, self.res)

    def assertequals(self, jsonpathkey='', exp_value=''):
        """
        断言返回结果里面键的值和期望值相等
        :param jsonpathkey: 需要断言的键
        :param exp_value: 期望值
        :return:
        """
        # 获取实际结果，如果没获取到就是字符串None
        try:
            act_value = str(jsonpath.jsonpath(self.res,jsonpathkey)[0])
        except Exception as e:
            act_value = 'None'

        # 关联
        exp_value = self.get_relation(exp_value)

        # 断言相等
        if str(act_value) == str(exp_value):
            self.__write_excel(1, act_value + '==' + exp_value)
        else:
            self.__write_excel(0, act_value + '==' + exp_value)

    def savejson(self, jsonpathkey='', parmaname=''):
        """
        从返回的json结果里面保存一个键的值，保存的参数名叫paramame
        :param keyname: 结果里面的键
        :param parmaname: 保存后的键
        :return:
        """
        # 获取键的值，如果没获取到就是字符串None
        try:
            key_value = str(jsonpath.jsonpath(self.res,jsonpathkey)[0])
        except Exception as e:
            key_value = 'None'

        self.relations[parmaname] = key_value
        self.__write_excel(1, self.relations)

    def str_to_dict(self, params):
        """
        url格式的参数字符串转成字典
        :param params: url格式的参数
        :return: 转换后的字典
        """
        if params is None:
            return None

        # 转换后的字典
        param_dict = {}
        # 先分割
        plist = params.split('&')
        for key_value in plist:
            if key_value == '':
                # 处理&后面没有键的情况
                pass
            else:
                index = key_value.find('=')
                if index > 0:
                    # 如果没有写等号的参数，就不要它
                    param_dict[key_value[0:index]] = key_value[index + 1:]

        return param_dict

    def get_relation(self, param=None):
        """
        把需要关联的字符串里面的{parmaname}的形式的字符串，我们替换为self.relations里面paramname键的值
        :param param: 需要关联的字符串参数
        :return: 关联后的字符串参数
        """
        if param is None:
            return None

        for key in self.relations:
            param = param.replace('{' + key + '}', self.relations[key])

        return param

    def __write_excel(self, status=0, msg=''):
        """
        写入用例执行的结果
        :param status: 执行结果状态
        :param msg: 需要写入的信息
        :return:
        """
        if status == 0:
            # 写入失败的状态
            self.writer.write(self.writer.row, 7, 'FAIL', 2)
        else:
            # 写入成功的状态
            self.writer.write(self.writer.row, 7, 'PASS', 3)

        # 写入用例执行的实际结果
        self.writer.write(self.writer.row, 8, str(msg))
